﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SurfaceCardsGameKit.Games.BasicGame;
using SurfaceCardsBoardLibrary.Interfaces;
using SurfaceCardsBoardLibrary;
using System.Windows;
using System.Collections;
using System.Reflection;
using System.Xml;
using System.Collections.Specialized;
using System.Windows.Media;
using SurfaceCardsGameKit.Dispositions;
using Microsoft.Surface.Presentation.Controls;
using System.Windows.Input;
using SurfaceCardsGameKit.Games.BlackJack;

namespace SurfaceCardsGameKit
{
    public class BlackJack : BasicGame
    {
        #region Private Property

        private XmlDocument xml = new XmlDocument();
        private Board board;

        private Deck MainDeck = new Deck();

        private Deck Dealer = new Deck();
        private Deck Player1 = new Deck();
        private Deck Player2 = new Deck();
        private Deck Player3 = new Deck();
        private Deck Player4 = new Deck();
        private Deck Player5 = new Deck();

        private bool Calculate = false;
        
        private List<ICard> cards = new List<ICard>();

        private List<DispositionOffset> disposition = new List<DispositionOffset>();


        public bool GatherButtonEnabled
        {
            get { return (bool)GetValue(GatherButtonEnabledProperty); }
            set { SetValue(GatherButtonEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for GatherButtonEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty GatherButtonEnabledProperty =
            DependencyProperty.Register("GatherButtonEnabled", typeof(bool), typeof(BlackJack), new UIPropertyMetadata(false));



        #endregion

        #region Public Property

        private DelegateCommand _gatherCardCommand;

        public ICommand GatherCardCommand
        {
            get
            {
                if (_gatherCardCommand == null)
                {
                    _gatherCardCommand = new DelegateCommand(
                    () => GatherCards());
                }
                return _gatherCardCommand;
            }
        }

        private void GatherCards()
        {
            IDeck[] decks = new IDeck[] { Player1, Player2, Player3, Player4, Player5, Dealer };

            foreach (var deck in decks)
            {
                deck.AutoRemoveWhenEmpty = false;
                var cards = deck.ToList();
                this.board.RemoveCardsFromDeck(deck, cards);
                this.board.AddCardsToDeck(MainDeck, cards);
                foreach (Card card in cards)
                    card.ShadowVisibility = Visibility.Hidden;
            }

            foreach (Card card in Cards.OfType<Card>().Where(c => c.Deck != MainDeck))
            {
                card.ShadowVisibility = Visibility.Hidden;
                this.board.AddCardToDeck(MainDeck, card);
            }

            NewGame();
        }

        #endregion

        #region constructor

        public BlackJack(Board board)
            : base(board)
        {
            this.board = board;
            this.Initialize();
        }
        #endregion

        #region Init

        private void Initialize()
        {
            this.InitDecks();
            this.InitializeCards();

            this.LoadValue();

            this.board.IsCollidePathEnabled = false;

            var GatherButton = new GatherCardButton();
            GatherButton.DataContext = this;
            this.ManipulableObjects.Add(GatherButton);
            GatherButton.Center = new Point(60, 60);
            GatherButton.Style = Application.Current.FindResource("BaseScatterViewItemStyle") as Style;
            
            this.GameBackground = Application.Current.FindResource("TapisBlackJack") as DrawingBrush;
           
            NewGame();
        }

        private void InitDecks()
        {
            this.DeckScatterViewItemStyle = Application.Current.FindResource("DeckScatterViewItemStyle") as Style;

            #region MainDeck

            this.MainDeck = this.CreateDeck();
            this.MainDeck.IsMosaicEnabled = false;
            this.MainDeck.IsEyeEnabled = false;
            this.MainDeck.IsMenuEnabled = false;
            this.MainDeck.CanMove = false;
            this.MainDeck.CanScale = false;
            this.MainDeck.CanRotate = false;
            this.MainDeck.CanRemoveByUser = true;
            this.MainDeck.AutoRemoveWhenEmpty = false;
            this.MainDeck.CardAddingFace = CardInDeckFace.BackUp;
            this.MainDeck.CardAddingPosition = CardInDeckPosition.Bottom;
            this.MainDeck.CardRemovingFace = CardInDeckFace.BackUp;
            this.MainDeck.Visibility = Visibility.Hidden;
            this.MainDeck.Center = new Point(924, 110);
            this.MainDeck.Orientation = -150;
            this.MainDeck.DeckDisposition = DeckDisposition.Stack;
            this.MainDeck.CanApplyFan = false;

            #endregion

            #region Dealer

            this.Dealer = this.CreateDeck();
            this.Dealer.IsMosaicEnabled = false;
            this.Dealer.IsEyeEnabled = false;
            this.Dealer.IsMenuEnabled = false;
            this.Dealer.CanMove = false;
            this.Dealer.CanScale = false;
            this.Dealer.CanRotate = false;
            this.Dealer.CanRemoveByUser = true;
            this.Dealer.AutoRemoveWhenEmpty = false;
            this.Dealer.CardAddingFace = CardInDeckFace.AsIs;
            this.Dealer.CardAddingPosition = CardInDeckPosition.Top;
            this.Dealer.CardRemovingFace = CardInDeckFace.FrontUp;
            this.Dealer.Visibility = Visibility.Hidden;
            this.Dealer.Center = new Point(528, 100);
            this.Dealer.Orientation = 0;
            this.Dealer.DeckDisposition = DeckDisposition.Stack;

            this.Dealer.DefaultWidth = 83;
            this.Dealer.DefaultHeight = 100;

            this.Dealer.CollectionChanged += new NotifyCollectionChangedEventHandler(d_CollectionChanged);

            #endregion

            #region Player1

            this.Player1 = this.CreateDeck();
            this.Player1.IsMosaicEnabled = false;
            this.Player1.IsEyeEnabled = false;
            this.Player1.IsMenuEnabled = false;
            this.Player1.CanMove = false;
            this.Player1.CanScale = false;
            this.Player1.CanRotate = false;
            this.Player1.CanRemoveByUser = true;
            this.Player1.AutoRemoveWhenEmpty = false;
            this.Player1.CardAddingFace = CardInDeckFace.FrontUp;
            this.Player1.CardAddingPosition = CardInDeckPosition.Top;
            this.Player1.CardRemovingFace = CardInDeckFace.FrontUp;
            this.Player1.Visibility = Visibility.Hidden;
            this.Player1.Center = new Point(192, 398);
            this.Player1.Orientation = 54.4;
            this.Player1.DeckDisposition = DeckDisposition.Stack;

            this.Player1.DefaultWidth = 83;
            this.Player1.DefaultHeight = 100;

            this.Player1.CollectionChanged += new NotifyCollectionChangedEventHandler(d_CollectionChanged);

            #endregion

            #region Player2

            this.Player2 = this.CreateDeck();
            this.Player2.IsMosaicEnabled = false;
            this.Player2.IsEyeEnabled = false;
            this.Player2.IsMenuEnabled = false;
            this.Player2.CanMove = false;
            this.Player2.CanScale = false;
            this.Player2.CanRotate = false;
            this.Player2.CanRemoveByUser = true;
            this.Player2.AutoRemoveWhenEmpty = false;
            this.Player2.CardAddingFace = CardInDeckFace.FrontUp;
            this.Player2.CardAddingPosition = CardInDeckPosition.Top;
            this.Player2.CardRemovingFace = CardInDeckFace.FrontUp;
            this.Player2.Visibility = Visibility.Hidden;
            this.Player2.Center = new Point(336, 504);
            this.Player2.Orientation = 16.8;
            this.Player2.DeckDisposition = DeckDisposition.Stack;

            this.Player2.DefaultWidth = 83;
            this.Player2.DefaultHeight = 100;

            this.Player2.CollectionChanged += new NotifyCollectionChangedEventHandler(d_CollectionChanged);

            #endregion

            #region Player3

            this.Player3 = this.CreateDeck();
            this.Player3.IsMosaicEnabled = false;
            this.Player3.IsEyeEnabled = false;
            this.Player3.IsMenuEnabled = false;
            this.Player3.CanMove = false;
            this.Player3.CanScale = false;
            this.Player3.CanRotate = false;
            this.Player3.CanRemoveByUser = true;
            this.Player3.AutoRemoveWhenEmpty = false;
            this.Player3.CardAddingFace = CardInDeckFace.FrontUp;
            this.Player3.CardAddingPosition = CardInDeckPosition.Top;
            this.Player3.CardRemovingFace = CardInDeckFace.FrontUp;
            this.Player3.Visibility = Visibility.Hidden;
            this.Player3.Center = new Point(530, 529);
            this.Player3.Orientation = 0;
            this.Player3.DeckDisposition = DeckDisposition.Stack;

            this.Player3.DefaultWidth = 83;
            this.Player3.DefaultHeight = 100;

            this.Player3.CollectionChanged += new NotifyCollectionChangedEventHandler(d_CollectionChanged);

            #endregion

            #region Player4

            this.Player4 = this.CreateDeck();
            this.Player4.IsMosaicEnabled = false;
            this.Player4.IsEyeEnabled = false;
            this.Player4.IsMenuEnabled = false;
            this.Player4.CanMove = false;
            this.Player4.CanScale = false;
            this.Player4.CanRotate = false;
            this.Player4.CanRemoveByUser = true;
            this.Player4.AutoRemoveWhenEmpty = false;
            this.Player4.CardAddingFace = CardInDeckFace.FrontUp;
            this.Player4.CardAddingPosition = CardInDeckPosition.Top;
            this.Player4.CardRemovingFace = CardInDeckFace.FrontUp;
            this.Player4.Visibility = Visibility.Hidden;
            this.Player4.Center = new Point(719, 499);
            this.Player4.Orientation = -20.6;
            this.Player4.DeckDisposition = DeckDisposition.Stack;

            this.Player4.DefaultWidth = 83;
            this.Player4.DefaultHeight = 100;

            this.Player4.CollectionChanged += new NotifyCollectionChangedEventHandler(d_CollectionChanged);

            #endregion

            #region Player5

            this.Player5 = this.CreateDeck();
            this.Player5.IsMosaicEnabled = false;
            this.Player5.IsEyeEnabled = false;
            this.Player5.IsMenuEnabled = false;
            this.Player5.CanMove = false;
            this.Player5.CanScale = false;
            this.Player5.CanRotate = false;
            this.Player5.CanRemoveByUser = true;
            this.Player5.AutoRemoveWhenEmpty = false;
            this.Player5.CardAddingFace = CardInDeckFace.FrontUp;
            this.Player5.CardAddingPosition = CardInDeckPosition.Top;
            this.Player5.CardRemovingFace = CardInDeckFace.FrontUp;
            this.Player5.Visibility = Visibility.Hidden;
            this.Player5.Center = new Point(872, 413);
            this.Player5.Orientation = -40.4;
            this.Player5.DeckDisposition = DeckDisposition.Stack;

            this.Player5.DefaultWidth = 83;
            this.Player5.DefaultHeight = 100;

            this.Player5.CollectionChanged += new NotifyCollectionChangedEventHandler(d_CollectionChanged);

            #endregion

        }

        protected override void InitializeDeck(DeckWaitingInitialization deck)
        {
            base.InitializeDeck(deck);

            ScatterViewItem svi = _board.ScatterView.GetScatterViewItemForItem(deck.Deck);

            if (deck.Deck.Count < 20 && deck.Deck != this.MainDeck)
            {
                deck.Deck.GetCardsDestinationRect = GetCardsDestination;
            }
        }

        public Rect GetCardsDestination()
        {
            var rect = new Rect(
                -10,
                0,
                149,
                150);
            return rect;
        }

        private void InitializeCards()
        {
            this.CardScatterViewItemStyle = Application.Current.FindResource("CardScatterViewItemStyle") as Style;
            
            int numStack = 1;

            this.CreateBrushesFor52Cards();
            for (int i = 0; i < numStack; i++)
            {
                this.Add52CardsToBoard();
            }
 
            using (this.MainDeck.DeferUpdateDisposition(false, false))
            {
                foreach (var card in this.board.Cards.OfType<Card>())
                {
                    card.CanTurnByUser = true;
                    card.IsBookEnabled = false;
                    card.IsFlipSoundEnabled = false;
                    card.CanMergeByUser = false;
                    this.board.AddCardToDeck(this.MainDeck as IDeck, card);
                }
            }

            DateTime seed = DateTime.Now;
            this.MainDeck.Shuffle(seed.Millisecond);

            this.MainDeck.UpdateDisposition(false, false);
        }

        #endregion

        #region BlackJack

        /*
         * Init property for a new game
         * */
        public void NewGame()
        {
            Calculate = false;
            GatherButtonEnabled = false;
        }

        void d_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            Deck d = sender as Deck;

            int val = Evaluate(d);

            // if Dealer >16  button new game enabled
            if (Evaluate(Dealer) > 16 )
            {
                GatherButtonEnabled = true;
            }

            // activate Evaluate Deck if Dealer shows cards
            if (Dealer.Count >= 2)
            {
                if (Dealer[0].IsFront == true
                    && Dealer[1].IsFront == true)
                {
                    Calculate = true;
                }
            }
                

            // If BlackJack
            if (val == 21 && d.Count<ICard>() == 2 && !d.Center.Equals(new Point(528, 100)))
            {
                foreach (Card card in d)
                {
                    card.ShadowColor = Colors.Blue;
                    card.ShadowMargin = new Thickness(-10);
                    card.ShadowVisibility = Visibility.Visible;
                }
            }
            else if (val > 21) // If Deck > 21
            {
                foreach (Card card in d)
                {
                    card.ShadowColor = Colors.Red;
                    card.ShadowMargin = new Thickness(-10);
                    card.ShadowVisibility = Visibility.Visible;
                }
            }
            else if (d.Center.Equals(new Point(528, 100)) && Calculate) // Deck Dealer
            {
                #region Player1

                if (val < Evaluate((IDeck)Player1)) // Player Win
                {
                    foreach (Card card in Player1)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Blue;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else if (val == Evaluate((IDeck)Player1)) // Play Draw
                {
                    foreach (Card card in Player1)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Yellow;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else // Player Loose
                {
                    foreach (Card card in Player1)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Red;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }

                #endregion
                #region Player2

                if (val < Evaluate((IDeck)Player2)) // Player Win
                {
                    foreach (Card card in Player2)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Blue;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else if (val == Evaluate((IDeck)Player2)) // Play Draw
                {
                    foreach (Card card in Player2)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Yellow;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else // Player Loose
                {
                    foreach (Card card in Player2)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Red;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }

                #endregion
                #region Player3

                if (val < Evaluate((IDeck)Player3)) // Player Win
                {
                    foreach (Card card in Player3)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Blue;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else if (val == Evaluate((IDeck)Player3)) // Play Draw
                {
                    foreach (Card card in Player3)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Yellow;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else // Player Loose
                {
                    foreach (Card card in Player3)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Red;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }

                #endregion
                #region Player4

                if (val < Evaluate((IDeck)Player4)) // Player Win
                {
                    foreach (Card card in Player4)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Blue;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else if (val == Evaluate((IDeck)Player4)) // Play Draw
                {
                    foreach (Card card in Player4)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Yellow;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else // Player Loose
                {
                    foreach (Card card in Player4)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Red;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }

                #endregion
                #region Player5

                if (val < Evaluate((IDeck)Player5)) // Player Win
                {
                    foreach (Card card in Player5)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Blue;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else if (val == Evaluate((IDeck)Player5)) // Play Draw
                {
                    foreach (Card card in Player5)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Yellow;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else // Player Loose
                {
                    foreach (Card card in Player5)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Red;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }

                #endregion
            }
            else if(Calculate) //Decks Player
            {
                if (val < Evaluate((IDeck)Dealer))  // Player loose
                {
                    foreach (Card card in d)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Red;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else if( val == Evaluate((IDeck)Dealer)) // Player Draw
                {
                    foreach (Card card in d)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Yellow;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
                else // Player Win
                {
                    foreach (Card card in d)
                    {
                        if (card.ShadowMargin != new Thickness(-10) && Calculate)
                        {
                            card.ShadowColor = Colors.Blue;
                            card.ShadowVisibility = Visibility.Visible;
                        }
                    }
                }
            }
        }


        #endregion

        #region IEvaluate Members

        public int Evaluate(IDeck deck)
        {
            if (deck == null)
                return 0;

            int val = 0;
            foreach (Card card in deck)
            {
                val+= this.GetValue(card);
            }

            if (val > 21)
            {
                foreach (Card card in deck)
                {
                    if (card.BasicCardValue.Number == BasicCardsNumber.Ace)
                    {
                        val -= 10;
                    }
                }
            }
            return val;
        }

        #endregion

        #region Load Value
        private void LoadValue()
        {
            try
            {
                this.xml.Load(Assembly.GetExecutingAssembly().GetManifestResourceStream("SurfaceCardsGameKit.Games.BlackJack.ValueBlackJack.xml"));
            }
            catch
            {
                throw new Exception("Error loading ValueBlackJack.xml");
            }
        }
        #endregion

        #region GetValue
        private int GetValue(ICard card)
        {
            BasicCardValue v = (BasicCardValue)card.CardValue;
            return this.GetValue(v.Number);
        }
        private int GetValue(BasicCardsNumber nb)
        {
            XmlElement root = this.xml.DocumentElement;
            XmlNodeList nodes = root.SelectNodes("//Cards");
            foreach (XmlNode node in nodes)
            {
                XmlNodeList tmp = node.ChildNodes;
                foreach (XmlNode n in tmp)
                {
                    XmlAttributeCollection a = n.Attributes;
                    if ((int)nb == Int32.Parse(a[0].Value))
                        return Int32.Parse(n.InnerText);
                }
            }
            return -1;
        }
        #endregion

    }
}
